home *** CD-ROM | disk | FTP | other *** search
- /*
- File: single.c
-
- Contains: xxx put contents here xxx
-
- Written by: Tom Biddulph
-
- Copyright: © 1992 by StarNine Technologies, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <1.10> 10/29/93 cac Add in the extended finder info to the finder field.
- <1.9> 10/20/93 cac Make single.c create things in version2 applesingle.
- <1.8> 6/23/93 cac Fix a joe bug from 4 years ago. Don't assume TOPS, always seek
- to the offet for writing the resoruce and don't assume we padded
- all entries to that point.
- <1.7> 12/16/92 bid Some systems are aligning our structure declarations on long
- word boundaries. This makes the "sizeof" operator return the
- wrong number of bytes when used explicitly to get the structure
- of the APPLESINGLE header. Instead, use a define that is the sum
- of the sizes of the elements of the structures in question.
- 10/20/92 bid This is the original version of
- "single.c". It has been moved from
- UNIX/SCCS control to MPW projector
- control.
-
- To Do:
- */
-
- /* @(#)(C) Copyright 1993 StarNine Technologies. All rights reserved. */
-
- static char sccs_ident[] ="@(#)Copyright StarNine Technologies 1993\t\
- Version 1.9 of single.c on 93/03/09 08:53:42";
- /*
- ** Copyright (c) 1988,1989 StarNine Technologies, Inc.
- ** All rights reserved.
- **
- ** Redistribution and use in source and binary forms are permitted
- ** provided that the above copyright notice and this paragraph are
- ** duplicated in all such forms and that any documentation,
- ** advertising materials, and other materials related to such
- ** distribution and use acknowledge that the software was developed
- ** by StarNine Technologies, Inc.
- **
- ** Mail*Link and StarNine are Trademarks of StarNine Technologies, Inc.
- ** StarNine Technologies, Inc.'s corporate name and/or its Trademarks
- ** CANNOT be used to endorse or promote products derived from
- ** this software without specific prior written permission signed by a
- ** corporate officer of StarNine Technologies, Inc. authorizing their use.
- **
- ** THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
- ** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- ** WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- ** THIS SOFTWARE IS NOT WARRANTED TO BE ERROR FREE.
- */
-
-
-
- /*
- ** single
- ** USAGE
- ** single [-o outputfile] [-s] [-c Creator] [-t Type] inputfile
- **
- ** This program will split an APPLESINGLE file into data and resource forks.
- ** It will also translate "PACKIT 1" format files.
- **
- */
- #include <stdio.h>
- #include <fcntl.h>
- #include <string.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/param.h>
- #include <errno.h>
- #include <netinet/in.h>
-
- #ifndef MAXNAMLEN
- #include <dirent.h>
- #endif /* MAXNAMLEN */
-
- #ifndef MAXNAMLEN
- #include <limits.h>
- #endif /* MAXNAMLEN */
-
- # define FSLENGTH 16
- # define PADLENGTH 256L
- # define FINDERPAD 0xE0
-
- /*
- ** This is what the header looks like on the disk.
- */
- struct diskheader
- {
- long disk_magic;
- long disk_version;
- char empty[FSLENGTH]; /* leave blank - this is only used in version 1 */
- short disk_numentries;
- };
-
- /*
- ** The sizeof operator does not always returned the value that
- ** we expect for the above structure. The APPLESINGLE header
- ** defines that the above items be present at the start of the
- ** file and that a long is a 68000 long word (4 bytes) and a
- ** short is a 68000 short word (2 bytes). The sizeof operator
- ** on some systems will return the size of the above struture,
- ** long word aligned, when will be 2 more bytes that the actual
- ** data that will be contained in the APPLESINGLE header itself.
- ** This problem happens on SUN SPARCSTATIONS (as well as others).
- */
- #define SIZEOF_DISKHEADER (sizeof(long)+sizeof(long)+FSLENGTH+sizeof(short))
-
- /*
- ** This is what the entry structure looks like on disk (it directly
- ** follows the diskheader).
- */
- struct appleentry
- {
- unsigned long entry_id;
- unsigned long entry_offset;
- unsigned long entry_length;
- };
- typedef struct diskheader diskheader;
- typedef struct appleentry appleentry;
-
- /*
- ** This structure is put together out of the above two strctures.
- ** This is what is visible to the rest of the world.
- */
- struct appleheader
- {
- diskheader header_disk;
- appleentry *header_entry;
- int header_fd; /* descriptor open to the resource file */
- int header_datafd; /* descriptor open to the data file (if it exists) */
- long header_mask; /* Keep track of which entries we are reading */
- struct stat header_stat; /* This is used to keep track of the size of the data file. */
- char *header_dataname; /* Name of the data file */
- };
-
- typedef struct appleheader appleheader;
-
- /*
- ** Macros to reduce typing...
- */
- # define header_magic header_disk.disk_magic
- # define header_version header_disk.disk_version
- # define header_numentries header_disk.disk_numentries
-
- /*
- ** The current magic numbers
- */
- # define APPLESINGLE 0x00051600
- # define APPLEDOUBLE 0x00051607
- # define APPLEUNKNOWN 0x00000000
-
- /*
- ** The only allowed version number.
- */
- # define VERSION 0x00010000
- # define VERSION_2 0x00020000
-
- /*
- ** Macros to test for types.
- */
- # define ISSINGLE(hdr) ((hdr->header_magic) == APPLESINGLE)
- # define ISDOUBLE(hdr) ((hdr->header_magic) == APPLEDOUBLE)
- # define ISAPPLE(hdr) ((ISSINGLE(hdr)) || (ISDOUBLE(hdr)))
-
- /*
- ** Legal entry ids.
- */
- # define ENTRY_DATAFORK 1
- # define ENTRY_RESOURCEFORK 2
- # define ENTRY_REALNAME 3
- # define ENTRY_COMMENT 4
- # define ENTRY_ICONBW 5
- # define ENTRY_ICONCOLOR 6
- # define ENTRY_FILEINFO 7
- # define ENTRY_FILES_DATE_INFO 8
- # define ENTRY_FINDERINFO 9
-
- # define ENTRY_MAX 10
-
- # ifndef min
- # define min(a,b) ((a) < (b) ? (a) : (b))
- # endif
-
- /*
- ** This string defines the type of the following entry in the
- ** "packed" file. The types are one of:
- ** "PMag" Uncompressed file
- ** "PMa4" Compressed file
- ** "PEnd" End of file.
- */
- typedef char ENCLHEADER [4];
-
- # define PACK_END "PEnd"
- # define PACK_COMP "PMa4"
- # define PACK_UNCOMP "PMag"
-
- /*
- ** Header for packed enclosure files. This is the structure that
- ** is put at the beginning of each entry in the file.
- **
- ** NOTE: Because the 386 does QUAD alignment, I had to remove
- ** the CRC short at the end. Also, this structure does not include
- ** the "type" header (above) which is also on each entry.
- */
- typedef struct
- {
- char fileNameSize;
- char fileName[63];
- char fileType[4];
- char fileCreator[4];
- short flags;
- short locked;
- long dataSize,
- resourceSize,
- createData,
- modDate;
- } ENCL;
-
- typedef short ENCLCRC;
-
-
- #define CREATOR_LEN 4
- #define TYPE_LEN 4
-
- #define BLANK_TYPE " "
- #define DEF_CREATOR "UNKN" /* Default creator type */
- #define DEF_TYPE "TEXT" /* Default Type */
- #define DEF_FILE "single.out" /* Default output file name */
- #define REALNAME 90L /* where we want to put the realname entry */
- #define FINDER 146L /* where we want to put the finder entry */
- #define FINDER_SIZE 32 /* size of the finder entry */
- #define CREATE_MODE 0755 /* Default mode for creat() */
-
- /*
- ** main
- ** Call get_start, and exit appropriately.
- */
- main(argc, argv)
- int argc;
- char *argv[];
- {
- /*
- ** call the UNIX version of this program
- */
- get_start(argc,argv);
- exit(0);
- }
- /*
- ** get_start
- ** Parse the arguments passed on the command line. If the arguments make
- ** sense, translate the input file.
- **
- ** Arguments
- ** argc Count of arguments
- ** argv List of arguments
- **
- ** Returns
- ** Nothing
- */
- get_start(argc,argv)
- int argc;
- char *argv[];
- {
- char *infile; /* Input file name */
- char *output; /* Output file name */
- char creator[CREATOR_LEN]; /* Creator to use */
- char type[TYPE_LEN]; /* Type to use */
- int got_o = 0; /* Flag for -o */
- int got_f = 0; /* Flag for -f */
- int got_s = 0; /* Flag for -s */
- int got_c = 0; /* Flag for -c */
- int got_t = 0; /* Flag for -t */
- int got_per = 0; /* Were we passed a file with a '%' at the beginning of the name? */
- int c; /* current flag returned by getopt */
- struct stat st; /* Used to test for the output file */
- int magic; /* Return value from get_magic */
- extern int opterr; /* getopt external */
- extern int optind; /* getopt external */
- extern char *optarg; /* getopt external */
-
-
- /*
- ** copy the default values into the creator and type fields
- */
- strncpy(creator, DEF_CREATOR, sizeof (creator));
- strncpy(type, DEF_TYPE, sizeof (type));
-
- /*
- ** handle options
- */
- while ( (c = getopt(argc, argv, "so:c:f:t:")) != EOF)
- {
- switch (c)
- {
- /*
- ** -s
- ** Split the input file into three files,
- ** (1) "output" containing the data fork.
- ** (2) "%output" containing the resource information.
- ** (3) "%houtput" containing only the resource header info.
- */
- case 's':
- got_s++;
- break;
-
- /*
- ** -o output
- ** What to call the output file.
- */
- case 'o':
- got_o++;
- output = optarg;
- break;
-
- /*
- ** -c Creator
- ** Set the "Creator" field. This is a 4 byte field used by
- ** Macintoshes. Setting this only makes sense when creating
- ** Macintosh files.
- */
- case 'c':
- got_c++;
- if (strlen(optarg) < 5)
- {
- strncpy((char *) creator, BLANK_TYPE, sizeof (creator));
- strncpy( (char *) creator, optarg, strlen(optarg));
- }
- else
- {
- fprintf(stderr,
- "The creator field needs to be 4 characters or less\n\n");
- usage();
- }
- break;
-
- /*
- ** -t Type
- ** Set the "Type" field. This is a 4 byte field used by
- ** Macintoshes. Setting this only makes sense when creating
- ** Macintosh files.
- */
- case 't':
- got_t++;
- if (strlen(optarg) < 5)
- {
- strncpy((char *) type, BLANK_TYPE, sizeof (type));
- strncpy((char *) type, optarg, strlen(optarg));
- }
- else
- {
- fprintf(stderr,
- "The type field needs to be 4 characters or less\n\n");
- usage();
- }
- break;
-
- /*
- ** -h, or any error.
- ** help -- print usage message
- */
- case 'h':
- case '?':
- default:
- usage();
- }
- }
-
- /*
- ** Make sure we got an input and an output file if appropriate.
- ** If the file is applesingle then convert to appledouble.
- ** If the file is appledouble then convert to applesingle.
- ** If the file is an unknown appletype then conver to applesingle.
- ** If the file is packed, then unpack the files as applesingle.
- */
- if ( optind >= argc )
- {
- fprintf(stderr,"An input file name needed\n\n", infile);
- usage();
- }
- if ( optind != (argc - 1) )
- {
- fprintf(stderr,"Only one input file allowed\n\n");
- usage();
- }
- infile = argv[optind];
-
-
- /*
- ** Figure out what kind of file this is. Based on that
- ** information, translate the file.
- */
- magic = get_magic(infile, &got_per);
-
- /*
- ** Packed APPLESINGLE files do not need an output file, so
- ** we should not check the existance of unneeded files.
- */
- if ( magic != 1 )
- {
- if ( !got_o )
- {
- output = DEF_FILE;
- printf("Using output file %s\n",output);
- }
- if ( stat(output,&st) != -1 )
- {
- fprintf(stderr,
- "Output file %s already exists\n",output);
- exit(1);
- }
- }
- switch(magic)
- {
- /*
- ** Neither Single, nor double.
- */
- case 0:
- if (got_s)
- {
- fprintf(stderr,
- "%s not in Apple Single format: -s option does not apply\n\n", infile);
- usage();
- }
- make_apple(infile,output,creator,type);
- break;
-
- /*
- ** Apple Single format
- */
- case 1:
- if (got_c)
- {
- fprintf(stderr,
- "%s is in Apple Single format: -c option does not apply\n\n", infile);
- usage();
- }
- if (got_t)
- {
- fprintf(stderr,
- "%s is in Apple Single format: -t option does not apply\n\n", infile);
- usage();
- }
- unmake_apple(infile,output,got_s,got_o);
- break;
- /*
- ** Apple Double format
- */
- case 2:
- if (got_c)
- {
- fprintf(stderr,
- "%s is in Apple Double format: -c option does not apply\n\n", infile);
- usage();
- }
- if (got_t)
- {
- fprintf(stderr,
- "%s is in Apple Double format: -t option does not apply\n\n", infile);
- usage();
- }
- if (got_s)
- {
- fprintf(stderr,
- "%s not in Apple Single format: -s option does not apply\n\n", infile);
- usage();
- }
- double_to_single(infile,output,got_per);
- break;
- }
- }
-
- /*
- ** usage
- **
- ** This function prints the usage messages, and quits.
- ** NOTE: This routine will exit.
- */
- usage()
- {
- fprintf (stderr,
- "usage: single [-s] [-c creator] [-t type] -o output input\n\n");
- fprintf (stderr, " -s create a seperate header and resource file\n");
- fprintf (stderr, " -c change the creator field in the finder\n");
- fprintf (stderr, " -t change the type field in the finder\n");
- fprintf (stderr, " -o the name of the output file\n");
- exit(1);
- }
-
- /*
- ** get_magic
- ** This function determines the format of a file.
- **
- ** Arguments
- ** name The name of the file to check.
- ** got_per whether the file we got starts with a percent
- ** This will be returned to the callee.
- **
- ** Returns
- ** 2 if the file is Apple Double
- ** 1 if the file is Apple Single
- ** 0 if the file is not an Apple format
- */
- get_magic(name, got_per)
- char *name;
- int *got_per;
- {
- register int fd; /* Descriptor used to read the file. */
- diskheader disk; /* How an Apple single or double format
- file is stored on disk. */
- int size; /* Size returned by read. */
- char temp[MAXPATHLEN]; /* Used to construct the '%' file for
- AppleDouble format resource forks. */
-
- /*
- ** open the file and try reading the header information
- */
- if((fd = open(name, O_RDONLY )) == -1)
- {
- fprintf(stderr, "get_magic: open on %s failed: ",name);
- perror("");
- close(fd);
- exit (1);
- }
- if((size = read(fd, &disk, SIZEOF_DISKHEADER)) == -1 )
- {
- perror ("get_magic: read failed");
- close(fd);
- exit (1);
- }
- (void) close(fd);
-
- if ( size < SIZEOF_DISKHEADER )
- return (0);
-
- *got_per = 0;
-
- /*
- ** check that the file is applesingle
- */
- if (disk.disk_magic == APPLESINGLE)
- {
- return(1);
- }
- else
- {
- /*
- ** if the magic number is apple double, then we must
- ** have gotten the percent file
- */
- if (disk.disk_magic == APPLEDOUBLE)
- {
- *got_per = 1;
- return(2);
- }
- else
- {
- /*
- ** other-wise we need to check whether the percent file
- ** (if it exists) is apple double. To do this we
- ** construct a new file name, with a '%' in front.
- */
- doubleName(name,temp,0);
-
- if ((fd = open(temp, O_RDONLY )) == -1)
- return (0);
-
- if ( read(fd, &disk, SIZEOF_DISKHEADER) < SIZEOF_DISKHEADER )
- {
- close(fd);
- return (0);
- }
- (void) close(fd);
- if (disk.disk_magic == APPLEDOUBLE)
- return(2);
- else
- return(0);
- }
- }
- }
-
- /*
- ** make_apple
- ** This function converts the input file into an Apple Single file.
- ** This routine will create a new file "output".
- **
- ** Arguments
- ** infile input file name
- ** output output file name
- ** creator what to put into the creator field in the finder
- ** type what to put into the type field in the finder
- **
- ** Returns
- ** Nothing
- */
- make_apple(infile,output,creator,type)
- char *infile;
- char *output;
- char *creator;
- char *type;
- {
- register int fd; /* Descriptor to the new file */
-
- /*
- ** Create and open the output file and open it.
- */
- if ((fd = creat(output,CREATE_MODE)) == -1)
- {
- fprintf(stderr, "make_apple: create of %s failed ",output);
- perror("");
- exit(1);
- }
-
- /*
- ** Write the header information.
- */
- write_header(fd,infile);
-
- /*
- ** Write the finder information and data, write_rest will close fd.
- */
- write_rest(fd, infile, creator, type);
- }
-
- /*
- ** write_header
- ** This function writes the Apple Single header information
- ** to the output file.
- **
- ** Arguments
- ** fd open file descriptor to the output file
- ** infile the file to convert to Apple Single format.
- **
- ** Returns
- ** Nothing
- */
- write_header(fd,infile)
- register int fd;
- char *infile;
- {
- diskheader disk; /* On disk header structure for Apple Single */
- appleentry entry; /* On disk structure for each entry */
- struct stat buf; /* Used to determine the size of the entry */
- char *lastPart;
-
- /*
- ** set up the information for the header and write it to the file
- */
- memset(&disk, 0, sizeof(diskheader));
- disk.disk_magic = APPLESINGLE;
- disk.disk_version = VERSION_2;
- disk.disk_numentries = 3;
- if ( write(fd, &disk, SIZEOF_DISKHEADER) != SIZEOF_DISKHEADER )
- {
- perror("write_header: write failed");
- close(fd);
- exit(1);
- }
-
- /*
- ** set up and write the entry information for the finder
- */
- entry.entry_id = ENTRY_FINDERINFO;
- entry.entry_offset = FINDER;
- entry.entry_length = FINDER_SIZE;
- if ( write(fd, &entry, sizeof(entry)) != sizeof(entry) )
- {
- perror("write_header: write of finder info failed");
- close(fd);
- exit(1);
- }
-
- /*
- ** set up the realname entry
- */
- entry.entry_id = ENTRY_REALNAME;
- entry.entry_offset = REALNAME;
- /*
- ** write the original file name, but only the last
- ** portion of a potentially full pathname.
- */
- if((lastPart = strrchr(infile,'/')) == NULL)
- lastPart = infile;
- else
- lastPart++;
- entry.entry_length = strlen(lastPart);
- if ( write(fd, &entry, sizeof(entry)) != sizeof(entry) )
- {
- perror("write_header: write of finder info failed");
- close(fd);
- exit(1);
- }
-
- /*
- ** set up and write the entry information for the data fork
- */
- entry.entry_id = ENTRY_DATAFORK;
- entry.entry_offset = PADLENGTH;
- if( stat(infile,&buf) == -1)
- {
- perror("write_header: stat failed");
- close(fd);
- exit(1);
- }
- entry.entry_length = buf.st_size;
- if ( write(fd, &entry, sizeof(entry)) != sizeof(entry) )
- {
- perror("write_header: write data fork failed");
- close(fd);
- exit(1);
- }
- }
-
- /*
- ** write_rest
- ** This function writes the finder information and data.
- ** Note, this function will close fd.
- **
- ** Arguments
- ** fd open file descriptor to the output file
- ** infile the file to convert to Apple Single format.
- ** creator what to put in the creator field in the finder
- ** type what to put in the type field in the finder
- **
- ** Returns
- ** Nothing
- */
- write_rest(fd, infile, creator, type)
- register int fd;
- char *infile;
- char *creator;
- char *type;
- {
- register int ifd; /* Used to read infile */
- register int len; /* Return value from read */
- char buf[BUFSIZ]; /* Used to read infile */
- char *lastPart; /* the last part of the name */
-
- /*
- ** First, seek to where the "real name" goes
- */
- if((lseek(fd, REALNAME, 0)) == -1)
- {
- perror("write_rest: lseek to REALNAME offset failed");
- (void) close(fd);
- exit(1);
- }
- /*
- ** write the original file name, but only the last
- ** portion of a potentially full pathname.
- */
- if((lastPart = strrchr(infile,'/')) == NULL)
- lastPart = infile;
- else
- lastPart++;
- if ( write(fd, lastPart, strlen(lastPart)) != strlen(lastPart) )
- {
- perror("write_rest: write of infile name failed");
- (void) close(fd);
- exit(1);
- }
-
- /*
- ** next seek to where the finder information is.
- */
- if((lseek(fd, FINDER, 0)) == -1)
- {
- perror("write_rest: lseek to FINDER offset failed");
- (void) close(fd);
- exit(1);
- }
- /*
- ** write the creator and type information
- */
- if ( write(fd, type, TYPE_LEN) != TYPE_LEN )
- {
- perror("write_rest: write of type failed");
- (void) close(fd);
- exit(1);
- }
- if ( write(fd, creator, CREATOR_LEN) != CREATOR_LEN )
- {
- perror("write_rest: write of creator failed");
- (void) close(fd);
- exit(1);
- }
-
- /*
- ** lseek to the PADLENGTH for the resource piece
- ** TOPS requires this. PADLENGTH is relative to the beginning
- ** of the file.
- */
- if( lseek(fd, PADLENGTH, 0) == -1)
- {
- perror("write_rest: lseek failed");
- (void) close(fd);
- exit(1);
- }
-
- /*
- ** open the input file and write it's contents to the output
- ** file
- */
- if( (ifd = open(infile, O_RDONLY )) == -1)
- {
- fprintf(stderr, "write_rest: open of %s failed ",infile);
- perror("");
- (void) close(fd);
- exit(1);
- }
-
- /*
- ** Copy the contents of infile to the data fork of the out file.
- */
- for (;;)
- {
- /*
- ** Read the data, <=0 hopefully means EOF.
- */
- if((len = read(ifd, buf, sizeof (buf))) <= 0)
- break;
- /*
- ** Write the data to the output file.
- */
- if( write(fd, buf, len) != len )
- {
- perror("write_rest: write of data fork failed");
- (void) close(ifd);
- (void) close(fd);
- exit(1);
- }
- }
- (void) close(fd);
- (void) close(ifd);
- }
-
- /*
- ** unmake_apple
- ** This function splits the apple single file into the resource and data
- ** forks.
- **
- ** Arguments
- ** infile the file to convert to split
- ** output the name of the output file
- ** got_s whether we got a -s as an option
- ** got_s whether we got a -o as an option
- **
- ** Returns
- ** 0 on success
- ** -1 on error
- */
- unmake_apple(infile,output,got_s,got_o)
- char *infile;
- char *output;
- int got_s;
- int got_o;
- {
- diskheader disk; /* On disk structure of the file */
- register int fd; /* Descriptor of the file */
- appleentry entry[ENTRY_MAX]; /* Each entry (resource, data, etc.) */
- int i; /* Index variable */
- int data_num; /* Entry for the data fork */
- int unpack = 0; /* Does this file need to be unpacked? */
- char creator[CREATOR_LEN]; /* Creator of the file */
- char type[TYPE_LEN]; /* Type of the file */
- struct stat st; /* Used to check for output file */
-
- /*
- ** open the file and try reading the header information
- */
- if((fd = open(infile, O_RDONLY )) == -1)
- {
- fprintf(stderr, "unmake_apple: open of %s failed ",infile);
- perror("");
- exit(1);
- }
- /*
- ** Read the disk information in.
- */
- if( read(fd, &disk, SIZEOF_DISKHEADER) != SIZEOF_DISKHEADER )
- {
- perror ("unmake_apple: read of disk information failed");
- exit(1);
- }
-
- /*
- ** read all of the entries
- */
- for (i = 0; i < disk.disk_numentries; i++)
- {
- if( read(fd, &entry[i], sizeof(entry[i])) != sizeof(entry[i]) )
- {
- perror("unmake_apple: read of disk entry failed");
- exit (1);
- }
- }
- for (i = 0; i < disk.disk_numentries; i++)
- {
- /*
- ** save the entry number of the data fork for later use
- ** if the file is packed
- */
- if (entry[i].entry_id == ENTRY_DATAFORK)
- {
- data_num = i;
- }
- /*
- ** determine if the file is in packed format by looking at the
- ** finderinfo
- */
- if (entry[i].entry_id == ENTRY_FINDERINFO)
- {
- if( lseek(fd, entry[i].entry_offset, 0) == -1)
- {
- perror("unmake_apple: lseek failed");
- exit (1);
- }
- if( read(fd, creator, sizeof(creator)) == -1)
- {
- perror("unmake_apple: read of creator failed");
- exit (1);
- }
- if( read(fd, type, sizeof(type)) == -1)
- {
- perror("unmake_apple: read of type failed");
- close(fd);
- exit (1);
- }
- /*
- ** Check to see if it is in PACKIT format.
- */
- if ( (!(strncmp(creator, "PIT ", 4))) || (!(strncmp(type, "PIT ", 4))))
- {
- unpack++;
- }
- }
- }
-
- /*
- ** if the file is packed then unpack it.
- */
- if(unpack)
- {
- if ( got_o )
- {
- fprintf(stderr,"Can not specify output file for a packed file\n");
- exit(1);
- }
- unpack_file(fd, entry[data_num]);
- (void) close(fd);
- return(0);
- }
- if ( !got_o )
- {
- output = DEF_FILE;
- printf("Using output file %s\n",output);
- }
- if ( stat(output,&st) != -1 )
- {
- fprintf(stderr,"Output file %s already exists\n",output);
- exit(1);
- }
-
- /*
- ** create the appropriate files
- */
- make_header(disk, entry, output, got_s);
- make_res_data(fd, disk.disk_numentries, entry, output, got_s);
- if( !got_s )
- {
- pad_resource(output);
- }
- (void) close(fd);
-
- return(0);
- }
-
- /*
- ** make_header
- ** This function writes the header information for a file.
- **
- ** Arguments
- ** disk the disk header information in the input file
- ** entry array of the entry fields of the input file
- ** output the name of the output file
- ** got_s whether we got a -s as an option
- **
- ** Returns
- ** Nothing
- */
- make_header(disk, entry, output, got_s)
- diskheader disk;
- appleentry entry[ENTRY_MAX];
- char *output;
- int got_s;
- {
- register int fd; /* File descriptor to new file */
- char tmp[MAXPATHLEN];/* Name of the resource fork */
- short temp; /* Temp holder */
- int i; /* index variable */
- int have_data = 0; /* Number of data forks */
- appleentry nulls; /* Empty entry for padding */
-
- /*
- ** if we got a -s then create a file with %h followed by the name
- ** of the output file. Otherwise, create a file with % followed by the
- ** name of the ouput file
- */
- if (got_s)
- {
- doubleName(output,tmp,1);
- disk.disk_magic = APPLEUNKNOWN;
- }
- else
- {
- doubleName(output,tmp,0);
- disk.disk_magic = APPLEDOUBLE;
- }
- if ((fd = creat(tmp,CREATE_MODE)) == -1)
- {
- fprintf(stderr, "make_header: create of %s failed: ",tmp);
- perror("");
- exit(1);
- }
-
- /*
- ** since we are spilting the file don't write the entry for the data
- ** but we need to decrement the number of entries
- */
- temp = disk.disk_numentries;
- for(i = 0; i < disk.disk_numentries; i++)
- {
- if(entry[i].entry_id == ENTRY_DATAFORK)
- {
- have_data++;
- temp--;
- }
- }
- disk.disk_numentries = temp;
-
- /*
- ** write the disk information to the header
- */
- if ( write(fd, &disk, SIZEOF_DISKHEADER) != SIZEOF_DISKHEADER )
- {
- perror("make_header: write of disk structure failed");
- exit(1);
- }
-
- /*
- ** write all entries to the header except the data fork
- */
- for(i = 0; i < disk.disk_numentries; i++)
- {
- if(entry[i].entry_id != ENTRY_DATAFORK)
- {
- if( write(fd, &entry[i], sizeof(entry[i])) != sizeof (entry[i]) )
- {
- perror("make_header: write of entries failed");
- exit(1);
- }
- }
- }
- (void) memset((char *)&nulls, sizeof (nulls), '\0');
- for ( i = disk.disk_numentries ; i < ENTRY_MAX ; i++ )
- {
- if ( write(fd,&nulls, sizeof(nulls)) != sizeof(nulls) )
- {
- perror("make_header: write of null entry failed");
- exit(1);
- }
- }
-
- /*
- ** restore the number of entries
- */
- if(have_data)
- disk.disk_numentries += have_data;
-
- (void) close(fd);
- }
-
- /*
- ** make_res_data
- ** This function writes the resource and data forks
- **
- ** Arguments
- ** fd open file descriptor to the input file
- ** numentries the number of entries in the input file
- ** entry array of the entry fields of the input file
- ** output the name of the output file
- ** got_s whether we got a -s as an option
- **
- ** Returns
- ** 0 on success
- ** -1 on error
- */
- make_res_data(fd, numentries, entry, output, got_s)
- register int fd;
- short numentries;
- appleentry entry[ENTRY_MAX];
- char *output;
- int got_s;
- {
- register int rfd; /* Resource fork descriptor */
- register int dfd; /* Data fork descriptor */
- char *file; /* Pointer to the file name */
- char temp[MAXPATHLEN]; /* Storage for the file name */
- char buf[BUFSIZ]; /* Buffer for reading the data */
- int i; /* Index variable */
- int no_data = 1; /* Tells us if anything was ever
- ** written to the data fork.
- */
- long num = 0; /* Length of each entry */
- int len = 0; /* Length returned by read */
-
- doubleName(output,temp,0);
- file = temp;
-
- /*
- ** if we got a -s then create and open the %output file
- ** otherwise, just open it
- */
- if(got_s)
- {
- if ((rfd = creat(file,CREATE_MODE)) == -1)
- {
- fprintf(stderr, "make_res_data: creat of %s failed: ",file);
- perror("");
- exit(1);
- }
- }
- else
- {
- if((rfd = open(file, O_RDWR )) == -1)
- {
- fprintf(stderr, "make_res_data: open of %s failed: ",file);
- perror("");
- exit(1);
- }
- if ( lseek(rfd,0L,2) == -1 )
- {
- fprintf(stderr,"make_res_data: lseek failed: ");
- perror("");
- exit(1);
- }
- }
-
-
- /*
- ** create the output file for the data fork
- */
- if ((dfd = creat(output,CREATE_MODE)) == -1)
- {
- fprintf(stderr, "make_res_data: creat of %s failed: ",output);
- perror("");
- exit(1);
- }
-
- /*
- ** Write all of the data to the %output file unless
- ** it is the data fork in which case write it to output file.
- */
- for (i = 0; i < numentries; i++)
- {
- /*
- ** read the data
- */
- if( lseek(fd, entry[i].entry_offset, 0) != entry[i].entry_offset )
- {
- perror("make_res_data: lseek failed");
- exit(1);
- }
- /* !!!!always!!! seek to the position to write in the resource. */
- if( entry[i].entry_id != ENTRY_DATAFORK)
- {
- if( lseek(rfd, entry[i].entry_offset, 0) != entry[i].entry_offset )
- {
- perror("make_res_data: lseek failed");
- exit(1);
- }
- }
- num = entry[i].entry_length;
- while(num)
- {
- if((len = read(fd, buf, min(num, sizeof(buf)))) <= 0)
- {
- break;
- }
-
- /*
- ** write the data
- */
- if( entry[i].entry_id == ENTRY_DATAFORK)
- {
- /*
- ** if we have the data fork then write to the output
- */
- no_data = 0;
- if( write(dfd, buf, len) != len )
- {
- perror("make_res_data: write to data fork failed");
- exit(1);
- }
- }
- else
- {
- /*
- ** otherwise write to the %output file
- */
- if( write(rfd, buf, len) != len )
- {
- perror("make_res_data: write of fork failed");
- exit(1);
- }
- }
- num -= len;
- }
- }
- /*
- ** if there is no data fork then unlink the output file
- */
- if (no_data)
- (void) unlink(output);
- (void) close(fd);
- (void) close(dfd);
- (void) close(rfd);
- }
-
- /*
- ** pad_resource
- ** This function will pad the resource fork to PADLENGTH (256)
- ** if it is smaller than that. This is used only for APPLEDOUBLE files.
- **
- ** Arguments
- ** output output file name
- **
- ** Returns
- ** Nothing
- */
- pad_resource(output)
- char *output;
- {
- int fd; /* descriptor to the file */
- char temp[MAXPATHLEN]; /* Resource fork name of the file */
- struct stat st; /* Stat structure for determining the pad length */
- char eof; /* Temp for holding EOF */
-
- /*
- ** append a % to the file name
- */
- doubleName(output,temp,0);
-
- /*
- ** open this file and pad it if it is smaller than 256 bytes
- */
- if((fd = open(temp, O_RDWR )) == -1)
- {
- fprintf(stderr, "pad_resource: open of %s failed: ",temp);
- perror("");
- exit(1);
- }
- if ( stat(temp,&st ) == -1)
- {
- perror("pad_resource: stat of output file failed");
- exit(1);
- }
- if (st.st_size < PADLENGTH)
- {
- if ( lseek(fd, PADLENGTH-1, 0) == -1 )
- {
- perror("pad_resource: lseek(PADLENGTH - 1) failed");
- exit(1);
- }
- eof = EOF;
- if ( write(fd,&eof,1) != 1 )
- {
- perror("pad_resource: write(EOF) failed");
- exit(1);
- }
- }
- (void) close(fd);
- }
-
- /*
- ** This function converts an apple double file into an apple single file
- **
- ** Arguments
- ** infile the name of the input file
- ** output output file name
- ** whther the input file starts with a %
- **
- ** Returns
- ** 0 on success
- ** -1 on failure
- */
- double_to_single(infile, output, got_per)
- char *infile;
- char *output;
- int got_per;
- {
- diskheader disk; /* On disk layout of file */
- appleentry entry[ENTRY_MAX]; /* Structure of each entry */
- int fd; /* File descriptor */
- int rfd; /* Descriptor for resource file */
- int ofd; /* Descriptor for data file */
- int i; /* Index variable */
- long num; /* Number of bytes to write out */
- int len; /* Length returned by read */
- struct stat st; /* Used to determine number of bytes to write out */
- char file[MAXPATHLEN]; /* Name of the output file */
- char *file1; /* Pointer to input file */
- char temp1[MAXPATHLEN]; /* Another output file */
- char buf[BUFSIZ]; /* Buffer for reading file */
-
- file1 = infile;
- if(got_per)
- {
- /*
- ** we got the file starting with a percent.
- ** try opening the file without the percent.
- ** if we can't because the file does not exists then
- ** just create the output file and dump the input file into it.
- ** while changing the magic number from appledouble to
- ** applesingle
- */
- singleName(infile,file);
- if ((fd = open(file, O_RDONLY )) == -1)
- {
- if(errno == ENOENT)
- {
- /*
- ** create and open the output file
- */
- if ((ofd = creat(output,CREATE_MODE)) == -1)
- {
- fprintf(stderr, "double_to_single: creat of %s failed: ",output);
- perror("");
- exit(1);
- }
-
- /*
- ** open the input file
- */
- if((fd = open(infile, O_RDONLY )) == -1)
- {
- fprintf(stderr, "double_to_single: open on %s failed: ",infile);
- perror("");
- exit (1);
- }
-
- /*
- ** stat the input file
- ** so that we can figure out its size
- */
- if( stat(infile, &st) == -1)
- {
- perror ("double_to_single: stat failed");
- exit (1);
- }
-
- if( read(fd, &disk, SIZEOF_DISKHEADER) != SIZEOF_DISKHEADER )
- {
- perror ("double_to_single: read of header failed");
- exit (1);
- }
-
- /*
- ** change the magic number to applesingle
- */
- disk.disk_magic = APPLESINGLE;
-
- /*
- ** write the header
- */
- if( write(ofd, &disk, SIZEOF_DISKHEADER) != SIZEOF_DISKHEADER )
- {
- perror ("double_to_single: write of header failed");
- exit (1);
- }
-
- /*
- ** lseek past the header and read the rest
- ** into a buffer
- */
- if( lseek(fd, (long)SIZEOF_DISKHEADER, 0) == -1)
- {
- perror ("double_to_single: seek past header failed");
- exit (1);
- }
- if( lseek(ofd, (long)SIZEOF_DISKHEADER, 0) == -1)
- {
- perror ("double_to_single: seek on output file failed");
- exit (1);
- }
- num = st.st_size-SIZEOF_DISKHEADER;
- while(num)
- {
- if((len = read(fd, buf, min(num, sizeof(buf)))) <= 0)
- {
- break;
- }
-
- /*
- ** write the buffer
- */
- if((write(ofd, buf, len)) != len )
- {
- perror ("double_to_single: write of buffer failed");
- exit (1);
- }
- num -= len;
- }
-
-
- (void) close(fd);
- (void) close(ofd);
- return(0);
- }
- else
- {
- fprintf(stderr, "double_to_single: open on %s failed: ",file);
- perror("");
- exit(1);
- }
- }
- }
- else
- {
- /*
- ** open the input file since it does not start with a percent
- */
- strcpy(file, infile);
- doubleName(infile,temp1,0);
- file1 = temp1;
-
- if ((fd = open(file, O_RDONLY )) == -1)
- {
- fprintf(stderr, "double_to_single: open on %s failed: ",file);
- perror("");
- exit(1);
- }
-
- }
-
- /*
- ** open the file starting with the percent
- ** if it does not exists then exit since the
- ** file can't be apple double
- */
- if ((rfd = open(file1, O_RDONLY )) == -1)
- {
- fprintf(stderr, "double_to_single: open on %s failed: ",file1);
- perror("");
- exit(1);
- }
-
- /*
- ** create and open the output file
- */
- if ((ofd = creat(output,CREATE_MODE)) == -1)
- {
- fprintf(stderr, "double_to_single: create of %s failed: ",output);
- perror("");
- exit(1);
- }
-
- /*
- ** read the disk and header info from the resource file
- */
- if( read(rfd, &disk, SIZEOF_DISKHEADER) != SIZEOF_DISKHEADER )
- {
- perror ("double_to_single: read of resource header failed");
- exit (1);
- }
- for (i = 0; i < disk.disk_numentries; i++)
- {
- if( read(rfd, &entry[i], sizeof(entry[i]))
- != sizeof(entry[i]) )
- {
- perror("double_to_single: read of disk entries failed");
- exit (1);
- }
- }
-
- /*
- ** stat the data fork to get its size
- */
- if((stat(file,&st)) == -1)
- {
- perror("double_to_single: stat failed");
- exit(1);
- }
-
- /*
- ** set-up the header for the output file and entry info
- ** to include the data fork
- */
- disk.disk_magic = APPLESINGLE;
- entry[disk.disk_numentries].entry_id = ENTRY_DATAFORK;
- /*
- ** the length is the length of the data file
- */
- entry[disk.disk_numentries].entry_length = (long)st.st_size;
- if( stat(file1,&st) == -1)
- {
- perror("double_to_single: stat failed");
- exit(1);
- }
- /*
- ** the offset is after size of the resource fork
- */
- entry[disk.disk_numentries].entry_offset = st.st_size;
-
- /*
- ** write the header and entry info
- */
- disk.disk_numentries++;
- if ( write(ofd, &disk, SIZEOF_DISKHEADER) != SIZEOF_DISKHEADER )
- {
- perror("double_to_single: write of disk header failed");
- exit(1);
- }
- for (i = 0; i < disk.disk_numentries; i++)
- {
- if ( write(ofd, &entry[i], sizeof(entry[i])) != sizeof(entry[i]) )
- {
- perror("double_to_single: write of disk entries failed");
- exit(1);
- }
- }
-
- /*
- ** write the data and resource forks into the output file
- */
- for (i = 0; i < disk.disk_numentries; i++)
- {
- if( lseek(rfd, entry[i].entry_offset, 0) == -1)
- {
- perror("double_to_single: lseek to entry failed");
- exit(1);
- }
- if( lseek(ofd, entry[i].entry_offset, 0) == -1)
- {
- perror("double_to_single: lseek on output file to entry failed");
- exit(1);
- }
- /*
- ** read the data
- ** if the entry is data fork then read from the data fork file
- ** otherwise read from the resource fork file
- */
- num = entry[i].entry_length;
- while(num)
- {
- if((entry[i].entry_id) == ENTRY_DATAFORK)
- {
- if((len = read(fd, buf, min(num, sizeof(buf)))) <= 0)
- {
- break;
- }
- }
- else
- {
- if ((len = read(rfd, buf, min(num,sizeof(buf)))) <= 0)
- {
- break;
- }
- }
-
- /*
- ** write the buffer
- */
- if( write(ofd, buf, len) != len )
- {
- perror("double_to_single: write of data failed");
- exit(1);
- }
- num -= len;
- }
- }
-
- (void) close(fd);
- (void) close(rfd);
- (void) close(ofd);
- return(0);
- }
-
- /*
- ** unpack_file
- ** This function unpacks a packed apple file
- **
- ** Arguments
- ** fd the file descriptor to the input file
- ** entry the data fork entry information
- **
- ** Returns
- ** 0 on success
- ** -1 on failure
- */
- unpack_file(fd, entry)
- register int fd;
- appleentry entry;
- {
- diskheader disk; /* Structure for each file in the packed file */
- appleentry newentry[ENTRY_MAX]; /* For the entries in each packed file */
- ENCL encl; /* PACKIT structure for each enclosed file */
- ENCLCRC hcrc; /* CRC for ENCL header */
- ENCLHEADER header; /* Type of each packed file (PACK_COMP,
- PACK_UNCOMP, PACK_END) */
- char buf[BUFSIZ]; /* Used to read the file */
- char filename[MAXNAMLEN]; /* Output file name */
- int tfd; /* Output file descriptor */
- long num; /* Number of bytes to read/write */
- int len = 0; /* Value returned by read */
- int i; /* Index variable */
-
- memset(&disk, 0, sizeof(diskheader));
- /*
- ** seek to the data fork
- */
- if ( lseek (fd, entry.entry_offset, 0) == -1)
- {
- perror("unpack_file: initial lseek failed");
- exit(1);
- }
-
- /*
- ** the packed files are seperated by PACK_END
- ** read the files until we have a PACK_END string
- */
- while ( read(fd, header, sizeof(header)) != -1
- && (strncmp(header,PACK_END,sizeof (header))))
- {
- /*
- ** we don't support these kinds of packed files
- */
- if ( strncmp(header,PACK_UNCOMP,sizeof (header))
- && strncmp(header,PACK_COMP,sizeof (header)) )
- {
- fprintf(stderr,"Can only understand PMag, and PMa4 packed files\n");
- exit(1);
- }
-
- /*
- ** read the enclosure information
- */
- if( read(fd, &encl, sizeof(encl)) != sizeof(encl) )
- {
- perror("unpack_file: read of enclosure info failed");
- exit(1);
- }
- if( read(fd, &hcrc, sizeof(hcrc)) != sizeof(hcrc) )
- {
- perror("unpack_file: read of crc failed");
- exit(1);
- }
-
- /*
- ** encl.fileName is the realname of the packed file.
- ** create and open it.
- */
- strncpy(filename, encl.fileName, encl.fileNameSize);
- filename[encl.fileNameSize] = '\0';
- if ((tfd = creat(filename,CREATE_MODE)) == -1)
- {
- fprintf(stderr, "unpack_file: create of %s failed: ",filename);
- perror("");
- exit(1);
- }
-
- /*
- ** set-up and write the disk header info
- */
- disk.disk_magic = APPLESINGLE;
- disk.disk_version = VERSION_2;
- disk.disk_numentries = 4;
- if ( write(tfd, &disk, SIZEOF_DISKHEADER) != SIZEOF_DISKHEADER )
- {
- perror("unpack_file: write of disk header failed");
- exit(1);
- }
-
- /*
- ** set up the realname entry
- */
- newentry[0].entry_id = ENTRY_REALNAME;
- newentry[0].entry_offset = REALNAME;
- newentry[0].entry_length = encl.fileNameSize;
-
- /*
- ** set up the finderinfo entry
- */
- newentry[1].entry_id = ENTRY_FINDERINFO;
- newentry[1].entry_offset = FINDER;
- newentry[1].entry_length = FINDER_SIZE;
-
- /*
- ** set up the resourcefork entry
- */
- newentry[2].entry_id = ENTRY_RESOURCEFORK;
- newentry[2].entry_offset = PADLENGTH;
- newentry[2].entry_length = encl.resourceSize;
-
- /*
- ** set up the datafork entry
- */
- newentry[3].entry_id = ENTRY_DATAFORK;
- newentry[3].entry_offset = PADLENGTH + encl.resourceSize;
- newentry[3].entry_length = encl.dataSize;
-
- /*
- ** write all entries to the output
- */
- for (i=0; i < disk.disk_numentries; i++)
- {
- if( write(tfd, &newentry[i], sizeof(newentry[i])) != sizeof(newentry[i]) )
- {
- perror("unpack_file: write of entry fields failed");
- exit(1);
- }
- }
-
- /*
- ** write the realname entry data
- */
- if( lseek(tfd, newentry[0].entry_offset, 0) == -1)
- {
- perror("unpack_file: lseek for realname failed");
- exit(1);
- }
- if( write(tfd,encl.fileName, encl.fileNameSize) != encl.fileNameSize )
- {
- perror("unpack_file: write for realname failed");
- exit(1);
- }
-
- /*
- ** write the finderinfo entry data
- */
- if( lseek(tfd, newentry[1].entry_offset, 0) == -1)
- {
- perror("unpack_file: lseek for finder info failed");
- exit(1);
- }
- if( write(tfd, encl.fileType, sizeof(encl.fileType))
- != sizeof(encl.fileType) )
- {
- perror("unpack_file: write for type info failed");
- exit(1);
- }
- if( write(tfd,encl.fileCreator, sizeof(encl.fileCreator))
- != sizeof(encl.fileCreator) )
- {
- perror("unpack_file: write for creator info failed");
- exit(1);
- }
-
- /*
- ** write the resourcefork entry data
- */
- if( lseek(tfd, newentry[3].entry_offset, 0) == -1)
- {
- perror("unpack_file: lseek resource fork failed");
- exit(1);
- }
- num = encl.dataSize;
- while(num)
- {
- if((len = read(fd, buf, min(num,sizeof(buf)))) <= 0)
- {
- break;
- }
- if( write(tfd, buf, len) != len )
- {
- perror("unpack_file: write for resource fork failed");
- exit(1);
- }
- num -= len;
- }
-
- if( lseek(tfd, newentry[2].entry_offset, 0) == -1)
- {
- perror("unpack_file: lseek for data fork failed");
- exit(1);
- }
- /*
- ** write the datafork entry data
- */
- num = encl.resourceSize;
- while(num)
- {
- if( (len = read(fd, buf,len = min(num, sizeof(buf)))) <= 0)
- {
- break;
- }
- if( write(tfd, buf, len) != len )
- {
- perror("unpack_file: write for data fork failed");
- exit(1);
- }
- num -= len;
- }
-
- /*
- ** read past the last 2 bytes
- */
- if( read(fd, &hcrc, sizeof(hcrc)) != sizeof(hcrc) )
- {
- perror("unpack_file: read of final CRC failed");
- exit(1);
- }
- (void) close(tfd);
- }
- }
-
- /*
- ** doubleName
- ** Convert a file name into a resource fork name. This means adding
- ** either a '%', or a '%h' to the front of the last component of the
- ** file name (i.e. /a/b/c/file -> /a/b/c/%file).
- **
- ** Arguments
- ** input The initial file name
- ** output The place to put the new file name (assumed to have enough space)
- ** hname Boolean, should the prefix be "%", or "%h"?
- **
- ** Returns
- ** Nothing
- */
- doubleName(input,output,hname)
- char *input;
- char *output;
- int hname;
- {
- char *slash; /* The last '/' in the input file */
- char lastname[MAXNAMLEN];
- char *prefix; /* Prefix to change the lastname with */
- int len; /* Length of input name */
-
- if ( hname )
- prefix = "%h";
- else
- prefix = "%";
-
- if ( (len = strlen(input)) > 1 )
- {
- if ( input[len - 1] == '/' )
- input[len - 1] = 0;
- }
- if ( (slash = strrchr(input,'/')) == NULL )
- sprintf(output,"%s%s",prefix,input);
- else
- {
- /* A copy of the last component of the file name. */
- strcpy(lastname,slash + 1);
- strcpy(output,input);
- slash = &output[slash - input];
- strcpy(slash + 1,prefix);
- if ( hname )
- strcpy(slash + 3,lastname);
- else
- strcpy(slash + 2,lastname);
- }
- }
- /*
- ** singleName
- ** Convert a file name from a resource fork name, into the data fork name.
- ** The '%' prefix is striped off of the file name
- ** (i.e. /a/b/c/%file -> /a/b/c/file).
- **
- ** Arguments
- ** input The initial file name
- ** output The place to put the new file name (assumed to have enough space)
- ** Returns
- ** Nothing
- */
- singleName(input,output)
- char *input;
- char *output;
- {
- char *percent; /* Location of the last '%' in the file name. */
- char lastname[MAXNAMLEN];
-
- if ( (percent = strrchr(input,'%')) == NULL )
- strcpy(output,input);
- else
- {
- /* A copy of the last component of the file name. */
- strcpy(lastname,percent + 1);
- *percent = 0;
- strcpy(output,input);
- strcat(output,lastname);
- *percent = '%';
- }
- }
-
-
-